home *** CD-ROM | disk | FTP | other *** search
-
- #include <QuickTimeMusic.h>
- #include <stdio.h>
- #include <Resources.h>
-
- void CopyString(StringPtr src,StringPtr dst,unsigned maximumLength);
- AtomicInstrument NewAtomicInstrument(void);
- AtomicInstrument NewAtomicInstrumentFromSNDHandle(Handle sndH);
-
-
-
- void PrintP(StringPtr s);
- void PrintP(StringPtr s)
- {
- long x;
-
- x = *s++;
- while(x--)
- printf("%c",*s++);
- }
-
-
- OSErr GetTrackType(Track tr,OSType *trackTypeOut);
- OSErr GetTrackType(Track tr,OSType *trackTypeOut)
- {
- OSErr err = noErr;
- Media me;
- OSType trackType = 0;
-
- me = GetTrackMedia(tr);
- if(err = GetMoviesError())
- goto goHome;
-
- GetMediaHandlerDescription(me, &trackType, nil, nil);
- if(err = GetMoviesError())
- goto goHome;
-
- goHome:
- if(err)
- trackType = 0;
- if(trackTypeOut)
- *trackTypeOut = trackType;
- return err;
- }
-
-
-
-
-
-
- #define kSampleLength 256
-
-
- AtomicInstrument NewAtomicInstrument(void)
- {
- ComponentResult result;
- AtomicInstrument ai = 0;
- unsigned char *x = 0;
- long i;
- ToneDescription td;
- double a,b;
- InstSampleDescRec isd;
-
- x = (unsigned char *)NewPtrClear(kSampleLength);
- if(!x)
- goto goHome;
-
- result = QTNewAtomContainer(&ai);
- if(result)
- goto goHome;
-
- td.synthesizerType = kSoftSynthComponentSubType;
- td.synthesizerName[0] = 0;
- CopyString("\pSawtooth",td.instrumentName,31);
- td.instrumentNumber = 1;
- td.gmNumber = 0;
-
- {
- QTAtom keyrangeInfoAtom;
- result = QTInsertChild( ai, 0, kaiToneDescType, 1, 1,
- sizeof(ToneDescription),&td,nil );
- if(result)
- goto goHome;
-
- result = QTInsertChild( ai, 0, kaiKeyRangeInfoType, 1, 1, 0, nil, &keyrangeInfoAtom );
-
- isd.dataFormat = 'raw ';
- isd.numChannels = 1;
- isd.sampleSize = 8;
- isd.sampleRate = ((long)0x6e00)<<16;
- isd.sampleDataID = 23;
- isd.offset = 0;
- isd.numSamples = kSampleLength;
-
- isd.loopType = 0;
- isd.loopStart = 0;
- isd.loopEnd = kSampleLength;
-
- isd.pitchNormal = 57;
- isd.pitchLow = 0;
- isd.pitchHigh = 128;
-
- result = QTInsertChild( ai, keyrangeInfoAtom, kaiSampleDescType, 1, 1,
- sizeof(InstSampleDescRec), &isd, nil );
- }
-
- #define kaiSampleNameType 'snam'
-
- for(i = 0; i < kSampleLength; i++)
- x[i] = i;
-
- {
- QTAtom sminA = 0;
- Str255 sampleName;
-
- result = QTInsertChild(ai,0,kaiSampleInfoType, 23, 0, 0, nil, &sminA);
-
- result = QTInsertChild(ai,sminA, kaiSampleDataType, 23, 0,
- kSampleLength, x, nil);
-
- CopyString("\pQTMA Example Waveform",sampleName,255);
- result = QTInsertChild(ai,sminA, kaiSampleNameType, 1, 0,
- sampleName[0],sampleName+1,nil);
- }
-
- goHome:
- if(x)
- DisposePtr((Ptr)x);
- x = 0;
-
- if(result)
- {
- if(ai)
- QTDisposeAtomContainer(ai);
- ai = 0;
- }
- return ai;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- typedef struct
- {
- long partType; // subtype of the general event, kGeneralEventAtomicInstrument or kGeneralEventNoteRequest
- long partOffset; // number of *longwords* into the sample description for the part
- long partEventLength;
- long partNumber;
- } PartStuff;
-
- #define kMaxPartCount 100 // a random number, but we're putting this junk on the stack after all
- #define kEndMarker 0x60000000
-
-
- OSErr PullPartList(MusicDescriptionHandle descH,long *partCountOut,PartStuff *partStuff);
- OSErr PullPartList(MusicDescriptionHandle descH,long *partCountOut,PartStuff *partStuff)
- /*
- * walk the sample description, and fill in the partcount & partstuff list
- *
- * Each routine calls this one itself, just to keep us honest. Every time the partlist
- * is printed, the PrintPartList routine calls us. Each time we replace one of the
- * instruments, we're called. Avoids all problems with keeping the data in synch with itself.
- */
- {
- OSErr err = noErr;
- long partCount;
- PartStuff *psW;
- unsigned long *start,*end,*w;
- unsigned long x,y;
- long eventLength;
- long eventType;
- long eventSubtype;
- long i;
- MusicDescriptionPtr descP;
-
- descP = *descH;
-
- start = descP->headerData;
- end = (unsigned long *)( ((char *)descP) + descP->descSize);
-
- // • Make list of note request and atomic instrument events
- w = start;
- partCount = 0;
- psW = partStuff;
- while(w < end)
- {
- x = *w;
- qtma_EventLengthForward(w,eventLength);
- eventType = qtma_EventType(x);
- if(eventType == kGeneralEventType)
- {
- y = *(w + eventLength - 1);
- eventSubtype = qtma_GeneralSubtype(x,y);
- if(eventSubtype == kGeneralEventAtomicInstrument
- || eventSubtype == kGeneralEventNoteRequest)
- {
- psW->partType = eventSubtype;
- psW->partOffset = w - start;
- psW->partEventLength = eventLength;
- psW->partNumber = qtma_XPart(x,y);
- partCount++;
- psW++;
- }
- }
- else if(x == kEndMarker)
- w = end;
-
- w += eventLength;
- }
-
- *partCountOut = partCount;
-
- goHome:
- return err;
- }
-
-
- void CopyString(StringPtr src,StringPtr dst,unsigned maximumLength)
- /*
- * Copy from src to dst, where the string length is no more
- * than maximumLength. Affects maximumLength+1 bytes of course.
- */
- {
- long x;
-
- x = maximumLength;
- while(x >= 0)
- dst[x--] = 0;
-
- if(maximumLength > src[0])
- maximumLength = src[0];
-
- *dst++ = maximumLength;
- *src++;
-
- while(maximumLength--)
- *dst++ = *src++;
- }
-
-
- OSErr GetAtomicInstrumentName(AtomicInstrumentPtr aiP,Str255 instName);
- OSErr GetAtomicInstrumentName(AtomicInstrumentPtr aiP,Str255 instName)
- {
- AtomicInstrument ai;
- QTAtom toneA;
- OSErr err = noErr;
- ToneDescription td;
-
- instName[0] = 0;
-
- ai = &aiP; // fake
- toneA = QTFindChildByIndex(ai, nil, kaiToneDescType, 1, nil);
-
- err = QTCopyAtomDataToPtr(ai, toneA, false, sizeof(ToneDescription), &td, nil);
- if(err)
- goto goHome;
-
- CopyString(td.instrumentName,instName,255);
-
- goHome:
- return err;
- }
-
- OSErr PrintPartList(MusicDescriptionHandle descH);
- OSErr PrintPartList(MusicDescriptionHandle descH)
- {
- OSErr err = noErr;
- MusicDescriptionPtr descP;
- long partCount;
- PartStuff partStuff[kMaxPartCount],*psW;
- long i;
-
- PullPartList(descH,&partCount,partStuff);
-
- // • Print the names of the instruments
- printf("%ld parts in music track\n",partCount);
- for(i = 1; i <= partCount; i++)
- {
- psW = partStuff + i - 1;
- printf("part %ld: ",i);
- if(psW->partType == kGeneralEventAtomicInstrument)
- {
- Str255 instName;
-
- err = GetAtomicInstrumentName((AtomicInstrumentPtr) ((**descH).headerData + psW->partOffset + 1), instName);
- if(err)
- goto goHome;
- PrintP(instName);
- printf(" (atomic)");
- }
- else
- PrintP(((NoteRequest *)((**descH).headerData + psW->partOffset + 1))->tone.instrumentName);
- printf("\n");
- }
- printf("\n");
- goHome:
- return err;
- }
-
- OSErr ReplaceInstrument(MusicDescriptionHandle descH,long partIndex,AtomicInstrument ai,NoteRequest *nr);
- OSErr ReplaceInstrument(MusicDescriptionHandle descH,long partIndex,AtomicInstrument ai,NoteRequest *nr)
- /*
- * Replace a part with either an atomic instrument, or a noterequest (whichever is nonzero)
- */
- {
- OSErr err = noErr;
- long partCount;
- PartStuff partStuff[kMaxPartCount],*psW;
- long oldEventLength,newEventLength; // in longs
- long oldDescHLength,newDescHLength; // in bytes
- long eventShift; // in bytes
- unsigned long eventHead,eventTail,*eventBody;
- long oldPartEventByteOffset;
- char *base,*end;
-
- err = PullPartList(descH,&partCount,partStuff);
- if(err)
- goto goHome;
-
- if(partIndex > partCount || partIndex <= 0)
- {
- err = -1;
- goto goHome;
- }
-
- psW = partStuff + partIndex - 1;
-
- oldDescHLength = GetHandleSize((Handle)descH);
- oldEventLength = psW->partEventLength;
- oldPartEventByteOffset = ((char *)((**descH).headerData + psW->partOffset)) - ((char *)(*descH));
-
- if(ai)
- {
- newEventLength = (GetHandleSize(ai) + sizeof(long) - 1) / sizeof(long) + 2;
- qtma_StuffGeneralEvent(eventHead,eventTail,psW->partNumber,kGeneralEventAtomicInstrument,newEventLength);
- }
- else if(nr)
- {
- newEventLength = (sizeof(NoteRequest) + sizeof(long) - 1) / sizeof(long) + 2;
- qtma_StuffGeneralEvent(eventHead,eventTail,psW->partNumber,kGeneralEventNoteRequest,newEventLength);
- }
- else
- {
- err = -2;
- goto goHome;
- }
-
- eventShift = sizeof(long) * (newEventLength - oldEventLength);
-
- newDescHLength = oldDescHLength + eventShift;
-
-
- if(eventShift > 0)
- {
- SetHandleSize((Handle)descH,newDescHLength);
- base = (char *)(*descH);
- end = base + oldDescHLength;
- BlockMove(base + oldPartEventByteOffset,
- base + oldPartEventByteOffset + eventShift,
- end - (base + oldPartEventByteOffset));
- }
- else
- {
- eventShift = -eventShift;
- base = (char *)(*descH);
- end = base + oldDescHLength;
- BlockMove(base + oldPartEventByteOffset + eventShift,
- base + oldPartEventByteOffset,
- end - (base + oldPartEventByteOffset + eventShift));
- SetHandleSize((Handle)descH,newDescHLength);
- }
-
-
- (**descH).descSize = newDescHLength;
- (**descH).headerData[psW->partOffset] = eventHead;
- (**descH).headerData[psW->partOffset + newEventLength - 1] = eventTail;
-
- if(ai)
- BlockMove(*ai,(**descH).headerData + psW->partOffset + 1,sizeof(long) * (newEventLength - 2));
- else
- BlockMove(nr,(**descH).headerData + psW->partOffset + 1,sizeof(long) * (newEventLength - 2));
-
- goHome:
- return err;
- }
-
-
- OSErr MuckWithMusicTrackSampleDescription(Movie mo,Track tr);
- OSErr MuckWithMusicTrackSampleDescription(Movie mo,Track tr)
- {
- OSErr err = noErr;
- Media me;
- MusicDescriptionHandle descH;
- long i;
- long partCount;
- PartStuff partStuff[kMaxPartCount];
- Handle sndH = 0;
-
- sndH = GetResource('snd ',129);
-
- me = GetTrackMedia(tr);
- if(err = GetMoviesError())
- goto goHome;
-
- descH = (MusicDescriptionHandle)NewHandle(0);
-
- GetMediaSampleDescription(me, 1, (SampleDescriptionHandle)descH);
- if(err = GetMoviesError())
- goto goHome;
-
- // • Print the names of the instruments
- PrintPartList(descH);
-
- // • Make list of note request and atomic instrument events
- err = PullPartList(descH,&partCount,partStuff);
- if(err)
- goto goHome;
-
- // • Replace an instrument
- {
- AtomicInstrument ai = 0;
-
- // replace all but the last instrument with this atomic thingie
- ai = NewAtomicInstrumentFromSNDHandle(sndH);
- //ai = NewAtomicInstrument();
- for(i = 1; i <= partCount - 1; i++)
- err = ReplaceInstrument(descH,i,ai,nil);
-
- // replace the 3rd instrument, if there is one, with a GM instrument
- if(partCount >= 3)
- {
- NoteAllocator na;
- NoteRequest nr;
-
- nr.info.polyphony = 2;
- nr.info.typicalPolyphony = 0x00010000;
-
- na = OpenDefaultComponent(kNoteAllocatorComponentType,0);
- if(!na)
- {
- err = -1;
- goto goHome;
- }
- NAStuffToneDescription(na,40,&nr.tone);
- CloseComponent(na);
- err = ReplaceInstrument(descH,3,nil,&nr);
- }
-
- // Set the new sample description
- err = SetMediaSampleDescription(me,1,(SampleDescriptionHandle)descH);
- PrintPartList(descH);
-
- printf("Playing movie now; click to stop.\n\n");
-
- StartMovie(mo);
- while(!Button())
- MoviesTask(0,1000);
- while(StillDown())
- MoviesTask(0,1000);
- StopMovie(mo);
- }
-
- goHome:
- return err;
- }
-
- void main(void);
- void main(void)
- {
- StandardFileReply sfr;
- OSType fileType;
- Movie mo;
- Track tr,musicTrack;
- OSType trackType;
- short resRefNum;
- OSErr err = 0;
- long i,trackCount,musicTrackIndex;
- Boolean enteredMovies = false;
-
- // • Print something so SIOUX will fire up the toolbox and stuff
- printf("Music Movie Header Manipulation\n");
- printf("September 1996, dvb, Apple Computer\n\n");
-
- // • Open a file, or go home
- fileType = MovieFileType;
- StandardGetFilePreview(nil, 1, &fileType, &sfr);
- if(!sfr.sfGood)
- goto goHome;
-
- EnterMovies();
- enteredMovies = true;
-
- resRefNum = 0;
- err = OpenMovieFile(&sfr.sfFile, &resRefNum, fsRdPerm);
- if(err)
- goto goHome;
-
- mo = 0;
- err = NewMovieFromFile(&mo, resRefNum, nil, nil, 0, nil);
- if(err)
- goto goHome;
-
- // • Find the first music track, and disable everything else
- trackCount = GetMovieTrackCount(mo);
- if(err = GetMoviesError())
- goto goHome;
-
- musicTrackIndex = 0;
- musicTrack = 0;
-
- for(i = 1; i <= trackCount; i++)
- {
- tr = GetMovieIndTrack(mo, i);
- if(err = GetMoviesError())
- goto goHome;
-
- err = GetTrackType(tr,&trackType);
- if(err)
- goto goHome;
-
- if(!musicTrackIndex && trackType == MusicMediaType)
- {
- musicTrackIndex = i;
- musicTrack = tr;
- SetTrackEnabled(tr, true);
- if(err = GetMoviesError())
- goto goHome;
- }
- else
- {
- SetTrackEnabled(tr, false);
- if(err = GetMoviesError())
- goto goHome;
- }
- }
-
- if(!musicTrack)
- {
- printf("No music tracks in movie.\n");
- goto goHome;
- }
-
- err = MuckWithMusicTrackSampleDescription(mo,tr);
-
- goHome:
- if(err)
- printf("error: %d\n",err);
-
- if(resRefNum)
- {
- if(mo)
- DisposeMovie(mo);
- CloseMovieFile(resRefNum);
- }
- if(enteredMovies)
- ExitMovies();
-
- printf("All done with the Music Media Header Manipulation.\n\n");
- }
-
-
-
- typedef struct
- {
- union
- {
- SoundHeader s;
- CmpSoundHeader c;
- ExtSoundHeader e;
- } u;
- } CommonSoundHeader;
-
-
- OSErr ParseSnd(Handle sndH, InstSampleDescRec *sd, unsigned long *dataOffsetResult, unsigned long *dataSizeResult);
- OSErr ParseSnd(Handle sndH, InstSampleDescRec *sd, unsigned long *dataOffsetResult, unsigned long *dataSizeResult)
- /* Given an 'SND ' in a handle, fill out a QTMA InstSampleDescRec, and return the
- * offset in bytes into the handle of the audio data, and the size of the audio data, in bytes.
- */
- {
- CommonSoundHeader *sh;
- long dataOffset;
- OSErr err;
- long sizeMultiplier = 1;
-
- {
- char *w;
- long i;
-
- w = (char *)sd;
- for(i = 0; i < sizeof(InstSampleDescRec); i++)
- *w++ = 0;
- }
-
- sd->pitchNormal = 60;
- sd->pitchLow = 0;
- sd->pitchHigh = 127;
-
- err = GetSoundHeaderOffset((SndListHandle) sndH, &dataOffset);
- if (err != noErr)
- return (err);
-
- sh = (CommonSoundHeader *) (*sndH + dataOffset);
-
- switch (sh->u.s.encode)
- {
- case stdSH:
- sd->numSamples = sh->u.s.length;
- sd->sampleRate = sh->u.s.sampleRate;
- sd->sampleSize = 8;
- sd->numChannels = 1;
- sd->loopStart = sh->u.s.loopStart;
- sd->loopEnd = sh->u.s.loopEnd;
- sd->pitchNormal = sh->u.s.baseFrequency;
- dataOffset += ((char *)&sh->u.s.sampleArea) - ((char *)&sh->u);
- sd->dataFormat = 'raw ';
- break;
-
- case extSH:
- sd->numSamples = sh->u.e.numFrames;
- sd->sampleRate = sh->u.e.sampleRate;
- sd->sampleSize = sh->u.e.sampleSize;
- sd->numChannels = sh->u.e.numChannels;
- sd->loopStart = sh->u.e.loopStart;
- sd->loopEnd = sh->u.e.loopEnd;
- sd->pitchNormal = sh->u.e.baseFrequency;
- dataOffset += ((char *)&sh->u.e.sampleArea) - ((char *)&sh->u);
- if (sh->u.e.sampleSize == 8)
- sd->dataFormat = 'raw ';
- else
- sd->dataFormat = 'twos';
- break;
-
- case cmpSH:
- sd->numSamples = sh->u.c.numFrames;
- sd->sampleRate = sh->u.c.sampleRate;
- sd->sampleSize = sh->u.c.sampleSize;
- sd->numChannels = sh->u.c.numChannels;
- sd->loopStart = sh->u.c.loopStart;
- sd->loopEnd = sh->u.c.loopEnd;
- sd->pitchNormal = sh->u.c.baseFrequency;
- dataOffset += ((char *)&sh->u.c.sampleArea) - ((char *)&sh->u);
- switch ((short) sh->u.c.compressionID)
- {
- case fixedCompression:
- sd->dataFormat = sh->u.c.format;
- break;
- case notCompressed:
- if (sh->u.c.sampleSize == 8)
- sd->dataFormat = 'raw ';
- else
- sd->dataFormat = 'twos';
- break;
- case threeToOne:
- sd->dataFormat = 'MAC3';
- sizeMultiplier = 3;
- break;
- case sixToOne:
- sd->dataFormat = 'MAC6';
- sizeMultiplier = 6;
- break;
- }
- break;
- }
-
- if(sd->loopEnd - sd->loopStart < 20)
- sd->loopEnd = sd->loopStart = 0;
-
-
- if(dataOffsetResult)
- *dataOffsetResult = dataOffset;
-
- sizeMultiplier *= sd->numChannels;
- if(sd->sampleSize == 16)
- sizeMultiplier *= 2;
- if(dataSizeResult)
- *dataSizeResult = sd->numSamples * sizeMultiplier;
- return (noErr);
- }
-
-
-
-
-
-
-
-
-
-
- AtomicInstrument NewAtomicInstrumentFromSNDHandle(Handle sndH)
- {
- ComponentResult result;
- AtomicInstrument ai = 0;
- unsigned char *x = 0;
- long i;
- ToneDescription td;
- double a,b;
- InstSampleDescRec isd;
- unsigned long sndAudioOffset,sndAudioLength;
-
- x = (unsigned char *)NewPtrClear(kSampleLength);
- if(!x)
- goto goHome;
-
- result = QTNewAtomContainer(&ai);
- if(result)
- goto goHome;
-
- td.synthesizerType = kSoftSynthComponentSubType;
- td.synthesizerName[0] = 0;
- if(sndH)
- CopyString("\pSnd Resource",td.instrumentName,31);
- else
- CopyString("\pSawtooth",td.instrumentName,31);
- td.instrumentNumber = 1;
- td.gmNumber = 0;
-
- {
- QTAtom keyrangeInfoAtom;
- result = QTInsertChild( ai, 0, kaiToneDescType, 1, 1,
- sizeof(ToneDescription),&td,nil );
- if(result)
- goto goHome;
-
- result = QTInsertChild( ai, 0, kaiKeyRangeInfoType, 1, 1, 0, nil, &keyrangeInfoAtom );
-
- Debugger();
- if(sndH)
- {
- ParseSnd(sndH, &isd, &sndAudioOffset,&sndAudioLength);
- isd.sampleDataID = 23;
- }
- else
- {
- isd.dataFormat = 'raw ';
- isd.numChannels = 1;
- isd.sampleSize = 8;
- isd.sampleRate = ((long)0x6e00)<<16;
- isd.sampleDataID = 23;
- isd.offset = 0;
- isd.numSamples = kSampleLength;
-
- isd.loopType = 0;
- isd.loopStart = 0;
- isd.loopEnd = kSampleLength;
-
- isd.pitchNormal = 57;
- isd.pitchLow = 0;
- isd.pitchHigh = 128;
- }
-
- result = QTInsertChild( ai, keyrangeInfoAtom, kaiSampleDescType, 1, 1,
- sizeof(InstSampleDescRec), &isd, nil );
- }
-
- #define kaiSampleNameType 'snam'
-
- for(i = 0; i < kSampleLength; i++)
- x[i] = i;
-
- {
- QTAtom sminA = 0;
- Str255 sampleName;
-
- result = QTInsertChild(ai,0,kaiSampleInfoType, 23, 0, 0, nil, &sminA);
-
- if(sndH)
- {
- HLock(sndH);
- result = QTInsertChild(ai,sminA, kaiSampleDataType, 23, 0,
- sndAudioLength, (*sndH) + sndAudioOffset, nil);
- HUnlock(sndH);
- }
- else
- result = QTInsertChild(ai,sminA, kaiSampleDataType, 23, 0,
- kSampleLength, x, nil);
-
- if(sndH)
- CopyString("\pImported SND Waveform",sampleName,255);
- else
- CopyString("\pQTMA Example Waveform",sampleName,255);
- result = QTInsertChild(ai,sminA, kaiSampleNameType, 1, 0,
- sampleName[0],sampleName+1,nil);
- }
-
- goHome:
- if(x)
- DisposePtr((Ptr)x);
- x = 0;
-
- if(result)
- {
- if(ai)
- QTDisposeAtomContainer(ai);
- ai = 0;
- }
- return ai;
- }
-
-
-